package util {
import codec.ScrollDirectionPropertyCodec;
import codec.ScrollDetailPropertyCodec;
import codec.DateScrollDetailPropertyCodec;
import codec.KeyCodePropertyCodec;
import mx.automation.codec.DefaultPropertyCodec;

import codec.IAutomationPropertyCodec;
import automation.SeleFxPropertyDescriptor;
import automation.SeleFxPropertyDescriptor;
import agent.SeleFxAgent;

import mx.controls.*;
import mx.automation.IAutomationClass;
import mx.automation.IAutomationMethodDescriptor;
import mx.automation.IAutomationEventDescriptor;
import mx.automation.IAutomationPropertyDescriptor;

public class JavaConverter {
    public static function convertToJava(commandXML:String):String {
        var currentStepCount:int = 0;
        var commandRecords:XML = new XML(commandXML);
        var commandStep:XML = commandRecords.Step[currentStepCount];
        var javaString:String = "FlexRoot root = SeleniumFlex.create(flexDriver); \n";

        //used to capture frequently used id
        var idCache:Object = {};

        //before create a variable, it will be checked in this cache. if it exist different Name would he choosen
        var varCache:Object = {};

        while (commandStep) {

            var container:String = "root";
            var comPartObjects:Object = parse(commandStep.@id.toString());
            var commPart:Object = comPartObjects[comPartObjects.length - 1];
            var automationClassName:String = commPart["automationClassName"]
            var javaClassName:String = automationClassName.substring(4, automationClassName.length) + ".class";
            var idPart:String = "\"id=" + commPart["id"] + ", automationName=" + commPart["automationName"] + "\"";

            if (commPart["id"] == null || commPart["id"] == "null" || commPart["id"] == "" || commPart["id"] == "0") {

                var startIndex:int = 0;

                for (var j:int = comPartObjects.length - 1; j >= 0; j--) {
                    commPart = comPartObjects[j];
                    automationClassName = commPart["automationClassName"]
                    javaClassName = automationClassName.substring(4, automationClassName.length) + ".class";
                    idPart = "\"id=" + commPart["id"] + ", automationName=" + commPart["automationName"] + "\"";
                    cacheKey = javaClassName + "-" + idPart;
                    if (idCache[cacheKey] == null) {
                        continue;
                    } else {
                        startIndex = j + 1;
                        container = varCache[idCache[cacheKey]];
                        break;
                    }
                }

                for (var i:int = startIndex; i < comPartObjects.length; i++) {
                    commPart = comPartObjects[i];
                    automationClassName = commPart["automationClassName"]
                    javaClassName = automationClassName.substring(4, automationClassName.length) + ".class";
                    idPart = "\"id=" + commPart["id"] + ", automationName=" + commPart["automationName"] + "\"";
                    cacheKey = javaClassName + "-" + idPart;
                    if (idCache[cacheKey] == null) {

                        //variable declaration
                        var variableName:String = convertToLocalVarPattern(automationClassName);
                        if (varCache[variableName] != null) {
                            variableName = variableName + "_" + currentStepCount;
                        }
                        var variableType:String = automationClassName.substring(4, automationClassName.length);
                        var temString:String = variableType + " " + variableName;
                        javaString = javaString + temString + " = " + container + ".Flex(" + javaClassName + ", createAutomationIdMap(" + idPart + "));\n";
                        idCache[cacheKey] = variableName;
                        varCache[variableName] = variableName;
                        container = variableName;
                    } else {
                        javaString = javaString + idCache[cacheKey];
                    }
                }
            } else {
                automationClassName = commPart["automationClassName"]
                javaClassName = automationClassName.substring(4, automationClassName.length) + ".class";
                idPart = "\"" + commPart["id"] + "\"";
                var cacheKey:String = javaClassName + "-" + idPart;
                if (idCache[cacheKey] == null) {
                    variableName = commPart["id"];
                    if (varCache[variableName] != null) {
                        variableName = variableName + "_" + currentStepCount;
                    }
                    variableType = automationClassName.substring(4, automationClassName.length);
                    temString = variableType + " " + variableName;
                    javaString = javaString + temString + " = " + container + ".Flex(" + javaClassName + ", " + idPart + ");\n";
                    idCache[cacheKey] = commPart["id"];
                    varCache[variableName] = variableName;
                    container = variableName;
                } else {
                    javaString = javaString + idCache[cacheKey];
                }
            }


            var method:String = commandStep.@method.toString();
            var args:String = commandStep.Args.@value.toString();

            //javaString = javaString + "." + method + "(\"" + args + "\")";
            javaString = javaString + container + "." + method + "(" + decodeParam(automationClassName, method, args) + "); \n";
            ++currentStepCount;
            commandStep = commandRecords.Step[currentStepCount];
        }
        return javaString;
    }

    private static function decodeParam(className:String, methodName:String, args:String):String {
        trace("className [" + className + "] methodName [" + methodName + "] args[" + args + "]");
        var clazz:IAutomationClass = SeleFxAgent.UIAgent.automationManager.automationEnvironment.getAutomationClassByName(className);
        trace(" automation class [" + clazz + "]");
        var event:IAutomationEventDescriptor = clazz.getDescriptorForEventByName(methodName);
        trace(" automation event [" + event + "]");
        var eventProperties:Array = event.getArgDescriptors(null);
        var argsArray:Array = convertToArray(args);

        var param:String = "";

        for (var i:int = 0; i < eventProperties.length; i++) {
            var propertyDescriptor:SeleFxPropertyDescriptor = eventProperties[i] as SeleFxPropertyDescriptor;
            trace("Event Property Codec [" + propertyDescriptor.codecName + "]")
            var decoder:IAutomationPropertyCodec = SeleFxCodecHelper.getCodecHelper().getPropertyCodecByName(propertyDescriptor.codecName);
            trace("Event Property Decoder [" + decoder + "]")

            var dummyObj:Object = {};
            dummyObj["ctrlKey"] = null;
            dummyObj["shiftKey"] = null;
            dummyObj["altKey"] = null;
            dummyObj[propertyDescriptor.name] = null;

            var decodedParam:Object;
            var paramToDecoder:Object;
            
            if (argsArray.length >= 0 && argsArray.length > i) {
                paramToDecoder = argsArray[i];
            } else {
                paramToDecoder = propertyDescriptor.defaultValue;
            }

            if (decoder is KeyCodePropertyCodec) {
                decodedParam=paramToDecoder;
            } else {
                decoder.decode(null, dummyObj, paramToDecoder, propertyDescriptor, null);
                decodedParam = (propertyDescriptor.name in dummyObj ? dummyObj[propertyDescriptor.name] : null);
            }

            trace("decodedParam ::" + decodedParam + "and Param is [" + param + "]");

            if (decodedParam == null) continue;
            if (param != "") param = param + ",";

            if (decodedParam is String && (decoder is DateScrollDetailPropertyCodec || decoder is KeyCodePropertyCodec || decoder is ScrollDetailPropertyCodec || decoder is ScrollDirectionPropertyCodec)) {
                param = param + convertToStaticVarPattern(decodedParam.toString());
            } else {
                param = param + "\"" + decodedParam.toString() + "\"";
            }
        }

        return param;
    }

    private static function convertToArray(args:String):Array {
        var result:Array = args.split("_ARG_SEP_");
        return result;
    }

    private static function convertToLocalVarPattern(param:String):String {
        trace("convertToLocalVarPattern param [" + param + "]")
        return param.charAt(0).toLowerCase() + param.substring(1, param.length);
    }

    /*
     converts atBottom to AT_BOTTOM
     */
    private static function convertToStaticVarPattern(param:String):String {
        trace("convertToNamingPattern param [" + param + "]")
        if(param == param.toUpperCase()) return param;
        var convertedParam:String = "";
        for (var i:uint = 0; i < param.length; i++) {
            var charStrip:String = param.charAt(i);
            if (charStrip == charStrip.toUpperCase()) {
                convertedParam = convertedParam + "_" + charStrip;
            } else {
                convertedParam = convertedParam + charStrip.toUpperCase();
            }
        }
        return convertedParam;
    }

    private static function parse(id:String):Object {
        var comPartObjects:Array = [];
        var compParts:Array = id.split("|");
        for (var i:int = 1; i < compParts.length; i++) {
            var partObj:Object = new Object();
            var idParts:Array = compParts[i].split("}");
            for (var j:int = 0; j < idParts.length; j++) {
                var partName:Array = idParts[j].split("{");
                if (partName[0]) {
                    var pName:String = partName[0]
                    var pValue:String = partName[1].split(" ")[0];
                    partObj[pName] = pValue;
                }
            }
            comPartObjects[comPartObjects.length] = partObj;
        }

        return comPartObjects;
    }
}
}